﻿using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;

namespace WYD.Common
{
    public class Tools
    {
        /// <summary>
        /// 要分割的字符串 eg: 1,3,10,00
        /// </summary>
        /// <param name="str"></param>
        /// <param name="split">分割的字符串</param>
        /// <returns></returns>
        public static long[] SpitLongArrary(string str, char split = ',')
        {
            if (string.IsNullOrEmpty(str)) { return Array.Empty<long>(); }
            str = str.TrimStart(split).TrimEnd(split);
            string[] strIds = str.Split(split, (char)StringSplitOptions.RemoveEmptyEntries);
            long[] infoIdss = Array.ConvertAll(strIds, s => long.Parse(s));
            return infoIdss;
        }

        public static int[] SpitIntArrary(string str, char split = ',')
        {
            if (string.IsNullOrEmpty(str)) { return Array.Empty<int>(); }
            string[] strIds = str.Split(split, (char)StringSplitOptions.RemoveEmptyEntries);
            int[] infoIdss = Array.ConvertAll(strIds, s => int.Parse(s));
            return infoIdss;
        }
        public static T[] SplitAndConvert<T>(string input, char split = ',')
        {
            if (string.IsNullOrEmpty(input)) { return Array.Empty<T>(); }
            string[] parts = input.Split(split, (char)StringSplitOptions.RemoveEmptyEntries);
            T[] result =  Array.ConvertAll(parts, s => (T)Convert.ChangeType(s, typeof(T)));
            //for (int i = 0; i < parts.Length; i++)
            //{
            //    result[i] = (T)Convert.ChangeType(parts[i], typeof(T));
            //}

            return result;
        }

        /// <summary>
        /// 根据日期获取星期几
        /// </summary>
        public static string GetWeekByDate(DateTime dt)
        {
            var day = new[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
            return day[Convert.ToInt32(dt.DayOfWeek.ToString("d"))];
        }

        /// <summary>
        /// 得到这个月的第几周
        /// </summary>
        /// <param name="daytime">年月日</param>
        /// <returns>传递过来的时间是第几周</returns>
        public static int GetWeekNumInMonth(DateTime daytime)
        {
            int dayInMonth = daytime.Day;
            //本月第一天
            DateTime firstDay = daytime.AddDays(1 - daytime.Day);
            //本月第一天是周几
            int weekday = (int)firstDay.DayOfWeek == 0 ? 7 : (int)firstDay.DayOfWeek;
            //本月第一周有几天
            int firstWeekEndDay = 7 - (weekday - 1);
            //当前日期和第一周之差
            int diffday = dayInMonth - firstWeekEndDay;
            diffday = diffday > 0 ? diffday : 1;
            //当前是第几周,如果整除7就减一天
            int weekNumInMonth = ((diffday % 7) == 0
                ? (diffday / 7 - 1)
                : (diffday / 7)) + 1 + (dayInMonth > firstWeekEndDay ? 1 : 0);
            return weekNumInMonth;
        }
        /// <summary>
        /// 判断一个字符串是否为url
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsUrl(string str)
        {
            try
            {
                string Url = @"^http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?$";
                return Regex.IsMatch(str, Url);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }
        public static bool CheckUserName(string str)
        {
            try
            {
                string rg = @"^[a-z][a-z0-9-_]*$";
                return Regex.IsMatch(str, rg);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 计算密码强度
        /// </summary>
        /// <param name="password">密码字符串</param>
        /// <returns></returns>
        public static bool PasswordStrength(string password)
        {
            //空字符串强度值为0
            if (string.IsNullOrEmpty(password)) return false;

            //字符统计
            int iNum = 0, iLtt = 0, iSym = 0;
            foreach (char c in password)
            {
                if (c >= '0' && c <= '9') iNum++;
                else if (c >= 'a' && c <= 'z') iLtt++;
                else if (c >= 'A' && c <= 'Z') iLtt++;
                else iSym++;
            }

            if (iLtt == 0 && iSym == 0) return false; //纯数字密码
            if (iNum == 0 && iLtt == 0) return false; //纯符号密码
            if (iNum == 0 && iSym == 0) return false; //纯字母密码

            if (password.Length >= 6 && password.Length < 16) return true;//长度不大于6的密码

            if (iLtt == 0) return true; //数字和符号构成的密码
            if (iSym == 0) return true; //数字和字母构成的密码
            if (iNum == 0) return true; //字母和符号构成的密码

            return true; //由数字、字母、符号构成的密码
        }
        ///<summary>
        ///生成随机字符串 
        ///</summary>
        ///<param name="length">目标字符串的长度</param>
        ///<param name="useNum">是否包含数字，1=包含，默认为包含</param>
        ///<param name="useLow">是否包含小写字母，1=包含，默认为包含</param>
        ///<param name="useUpp">是否包含大写字母，1=包含，默认为包含</param>
        ///<param name="useSpe">是否包含特殊字符，1=包含，默认为不包含</param>
        ///<param name="custom">要包含的自定义字符，直接输入要包含的字符列表</param>
        ///<returns>指定长度的随机字符串</returns>
        public static string GetRandomString(int length, bool useNum, bool useLow, bool useUpp, bool useSpe, string custom)
        {
            byte[] b = new byte[4];
            System.Security.Cryptography.RandomNumberGenerator.Create().GetBytes(b);
            Random r = new(BitConverter.ToInt32(b, 0));
            string s = null, str = custom;
            if (useNum == true) { str += "0123456789"; }
            if (useLow == true) { str += "abcdefghijklmnopqrstuvwxyz"; }
            if (useUpp == true) { str += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; }
            if (useSpe == true) { str += "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; }
            for (int i = 0; i < length; i++)
            {
                s += str.Substring(r.Next(0, str.Length - 1), 1);
            }
            return s;
        }
        
        
        /// <summary>
        /// 生成RSA PEM格式的公钥和密钥
        /// </summary>
        /// <param name="strength">长度</param>
        /// <returns>Item2:公钥；Item1:私钥；</returns>
        public static KeyPairRSA CreateKeyPairRSA(int strength = 1024)
        {
            RsaKeyPairGenerator r = new RsaKeyPairGenerator();
            r.Init(new KeyGenerationParameters(new SecureRandom(), strength));
            AsymmetricCipherKeyPair keys = r.GenerateKeyPair();

            TextWriter privateTextWriter = new StringWriter();
            PemWriter privatePemWriter = new PemWriter(privateTextWriter);
            privatePemWriter.WriteObject(keys.Private);
            privatePemWriter.Writer.Flush();


            TextWriter publicTextWriter = new StringWriter();
            PemWriter publicPemWriter = new PemWriter(publicTextWriter);
            publicPemWriter.WriteObject(keys.Public);
            publicPemWriter.Writer.Flush();


            return new KeyPairRSA(publicTextWriter.ToString(), privateTextWriter.ToString());
        }

        /// <summary>
        /// RSA加密
        /// </summary>
        /// <param name="publicPem"></param>
        /// <param name="encryptStr">待加密的字符串</param>
        /// <returns>加密后的Base64</returns>
        public static string EncryptRSA(string publicPem, string encryptStr)
        {
            using (TextReader reader = new StringReader(publicPem))
            {
                AsymmetricKeyParameter? key = new PemReader(reader).ReadObject() as AsymmetricKeyParameter;
                Pkcs1Encoding pkcs1 = new Pkcs1Encoding(new RsaEngine());
                pkcs1.Init(true, key);//加密是true；解密是false;
                byte[] entData = Encoding.UTF8.GetBytes(encryptStr);
                entData = pkcs1.ProcessBlock(entData, 0, entData.Length);
                return Convert.ToBase64String(entData);
            }
        }

        /// <summary>
        /// RSA解密
        /// </summary>
        /// <param name="privatePem"></param>
        /// <param name="decryptStr"></param>
        /// <returns></returns>
        public static string DecryptRSA(string privatePem, string decryptStr)
        {
            using (TextReader reader = new StringReader(privatePem))
            {
                dynamic key = new PemReader(reader).ReadObject();
                var rsaDecrypt = new Pkcs1Encoding(new RsaEngine());
                if (key is AsymmetricKeyParameter)
                {
                    key = (AsymmetricKeyParameter)key;
                }
                else if (key is AsymmetricCipherKeyPair)
                {
                    key = ((AsymmetricCipherKeyPair)key).Private;
                }
                rsaDecrypt.Init(false, key);  //这里加密是true；解密是false  

                byte[] entData = Convert.FromBase64String(decryptStr);
                entData = rsaDecrypt.ProcessBlock(entData, 0, entData.Length);
                return Encoding.UTF8.GetString(entData);
            }
        }
        
        public static string GetMd5Hash(string input)
        {
            // 创建一个 MD5 实例
            using (MD5 md5Hash = MD5.Create())
            {
                // 将输入字符串转换为字节数组并计算哈希值
                byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

                // 创建一个 StringBuilder 来收集字节并创建字符串
                StringBuilder sBuilder = new StringBuilder();

                // 循环遍历哈希字节数组的每个字节，并格式化为十六进制字符串
                for (int i = 0; i < data.Length; i++)
                {
                    sBuilder.Append(data[i].ToString("x2"));
                }

                // 返回十六进制字符串
                return sBuilder.ToString();
            }
        }
    }

    public record KeyPairRSA(string? PublicPem, string? PrivatePem);
}
